package com.cgy.utils.base.reflect.stream;

import javassist.*;

/**
 * @author CH
 */
public class ReflectOperationStreamBuilder {

    private final Class<?> classes;
    private CtClass ctClass = null;

    public ReflectOperationStreamBuilder(Class<?> classes) {
        this.classes = classes;
        ClassPool classPool = ClassPool.getDefault();
        try {
            this.ctClass = classPool.get(classes.getName());
        } catch (NotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 往方法最后插入代码
     * @param methodName
     * @param code
     * @return
     */
    public ReflectOperationStreamBuilder insertAfter(final String methodName, final String code) {
        return insertCode(methodName, 0, 1, code);
    }
    /**
     * 往方法最后插入代码
     * @param methodName
     * @param code
     * @return
     */
    public ReflectOperationStreamBuilder insertBefore(final String methodName, final String code) {
        return insertCode(methodName, -1, 1, code);
    }
    /**
     * 往方法{line}插入代码
     * @param methodName
     * @param line
     * @param code
     * @return
     */
    public ReflectOperationStreamBuilder insertLine(final String methodName, final int line, final String code) {
        return insertCode(methodName, line, 0, code);
    }
    /**
     * 插入代码
     *
     * @param methodName 方法
     * @param where      位置
     * @param line      第几行
     * @param code       代码
     * @return
     */
    public ReflectOperationStreamBuilder insertCode(final String methodName, final int line, final int where, final String code) {
        CtMethod declaredMethod = null;
        try {
            declaredMethod = ctClass.getDeclaredMethod(methodName);
        } catch (NotFoundException e) {
            e.printStackTrace();
        }

        if (null != declaredMethod) {
            try {
                if (0 == where) {
                    declaredMethod.insertAt(line, code);
                } else if (1 == where) {
                    declaredMethod.insertAfter(code);
                } else {
                    declaredMethod.insertBefore(code);
                }
            } catch (CannotCompileException e) {
                e.printStackTrace();
            }
        }

        return this;
    }
}
